#include "w5500/w5500_port.h"
#include "spi.h"
#include "string.h"
#include "stdio.h"
#include "./device/device.h"
#include "rtthread.h"


static struct rt_semaphore w5500_tx_sem;
static struct rt_semaphore w5500_rx_sem;
//extern osSemaphoreId_t W5500_DMA_TX_SemHandle;
//extern osSemaphoreId_t W5500_RX_SemHandle;

#define W5500_RST_H HAL_GPIO_WritePin(LAN_RST_GPIO_Port, LAN_RST_Pin, GPIO_PIN_SET);
#define W5500_RST_L HAL_GPIO_WritePin(LAN_RST_GPIO_Port, LAN_RST_Pin, GPIO_PIN_RESET);
#define W5500_CS_H HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_SET);
#define W5500_CS_L HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_RESET);

uint8_t RevBuf[2048];
uint8_t str[100];

wiz_NetInfo gWIZNETINFO = {
    .mac = {0x78, 0x83, 0x68, 0x88, 0x56, 0x72},
    .ip = {192, 168, 0, 240},
    .sn = {255, 255, 255, 0},
    .gw = {192, 168, 0, 1},
    .dns = {8, 8, 8, 8},
    .dhcp = NETINFO_STATIC};

void W5500_RESET(void)
{
    // reset W5500
    W5500_RST_L;
    rt_thread_delay(50);
    W5500_RST_H;
    rt_thread_delay(100);
}
uint8_t memsize[2][8] = {{8, 2, 2, 4, 0, 0, 0, 0},
                        {8, 2, 2, 4, 0, 0, 0, 0}};
uint8_t Use_socket[3] = {0};
// 初始化芯片参数
void ChipParametersConfiguration(void)
{
    uint8_t tmp;
    if (ctlwizchip(CW_INIT_WIZCHIP, (void *)memsize) == -1)
    {
        // while (1)
        //     ;
    }

    if (ctlwizchip(CW_GET_PHYLINK, (void *)&tmp) == -1)
    {
        // while (1)
        //     ;
    }
    if (tmp == PHY_LINK_OFF)
    {
        rt_kprintf("PHY LINK OFF\r\n");
    }
    else if (tmp == PHY_LINK_ON)
    {
        rt_kprintf("PHY LINK ON\r\n");
    }
    // do
    // {
    //     if (ctlwizchip(CW_GET_PHYLINK, (void *)&tmp) == -1)
    //     {
    //         while (1)
    //             ;
    //     }
    // } while (tmp == PHY_LINK_OFF);
}

// 初始化网络参数 mac ip等
void NetworkParameterConfiguration(void) // Intialize the network information to be used in WIZCHIP
{
    uint8_t ip[4];
    uint8_t tmpstr[6];
    memcpy(gWIZNETINFO.ip, g_qf_device.phy.IP, 4);
    memcpy(gWIZNETINFO.sn, g_qf_device.phy.MASK, 4);
    memcpy(gWIZNETINFO.gw, g_qf_device.phy.Gateway, 4);
    memcpy(gWIZNETINFO.mac, g_qf_device.phy.MAC, 4);
    ctlnetwork(CN_SET_NETINFO, (void *)&gWIZNETINFO);
    ctlnetwork(CN_GET_NETINFO, (void *)&gWIZNETINFO);
//    ctlwizchip(CW_GET_ID, (void *)tmpstr);

    if (gWIZNETINFO.dhcp == NETINFO_DHCP)
    {
        // rt_kprintf("\r\n=== %s NET CONF : DHCP ===\r\n", (char *)tmpstr);
    }
    else
    {
        // rt_kprintf("\r\n=== %s NET CONF : Static ===\r\n", (char *)tmpstr);
    }
    rt_kprintf("===========================\r\n");
    getSIPR(ip);
    rt_kprintf("IP : %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3]);
    getSUBR(ip);
    rt_kprintf("SN : %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3]);
    getGAR(ip);
    rt_kprintf("GW : %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3]);
    rt_kprintf("===========================\r\n");
}

void SPI_WriteByte(uint8_t TxData)
{
    uint8_t data;
//    while(__HAL_SPI_GET_FLAG(&hspi2,SPI_FLAG_TXE) == RESET);
    HAL_SPI_Transmit(&hspi2,&TxData,1,0);
}

uint8_t SPI_ReadByte(void)
{
    uint8_t data = 0;
//    while(__HAL_SPI_GET_FLAG(&hspi2,SPI_FLAG_RXNE) == RESET);
    HAL_SPI_Receive(&hspi2,&data,1,0);

    return data;
}

void SPI_ReadBurst(uint8_t *pBuf, uint16_t len)
{

    rt_sem_take(&w5500_rx_sem,RT_WAITING_FOREVER);
    HAL_SPI_Receive_IT(&hspi2, pBuf, len);
}

void SPI_WriteBurst(uint8_t *pBuf, uint16_t len)
{

    rt_sem_take(&w5500_tx_sem,RT_WAITING_FOREVER);
    HAL_SPI_Transmit_IT(&hspi2, pBuf, len);
}

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
    if (hspi->Instance == hspi2.Instance)
    {
        rt_interrupt_enter();          //在中断中一定要调用这对函数，进入中断
        rt_sem_release(&w5500_tx_sem);
        rt_interrupt_leave();    //在中断中一定要调用这对函数，离开中断
    }
}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
    if (hspi->Instance == hspi2.Instance)
    {
        rt_interrupt_enter();          //在中断中一定要调用这对函数，进入中断
        rt_sem_release(&w5500_rx_sem);
        rt_interrupt_leave();    //在中断中一定要调用这对函数，离开中断
    }
}

void SPI_CrisEnter(void)
{
    // __set_PRIMASK(1);
}

void SPI_CrisExit(void)
{
    // __set_PRIMASK(0);
}

void SPI_CS_Select(void)
{
    W5500_CS_L;
}

void SPI_CS_Deselect(void)
{
    W5500_CS_H;
}

// W5500初始化
int W5500_ChipInit(void)
{
    /* 初始化串口接收数据的信号量 */
    rt_sem_init(&(w5500_rx_sem), "w5500_rx_sem", 1, RT_IPC_FLAG_FIFO);
    rt_sem_init(&(w5500_tx_sem), "w5500_tx_sem", 1, RT_IPC_FLAG_FIFO);
    
    W5500_RESET();
    reg_wizchip_cris_cbfunc(SPI_CrisEnter, SPI_CrisExit);       // 注册临界函数
    reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect);      // 注册SPI片选函数
    reg_wizchip_spi_cbfunc(SPI_ReadByte, SPI_WriteByte);        // 注册SPI读写函数
    reg_wizchip_spiburst_cbfunc(SPI_ReadBurst, SPI_WriteBurst); // 注册SPI快速读写函数
    
//    setSHAR(gWIZNETINFO.mac);/*配置Mac地址*/
//    setSUBR(gWIZNETINFO.sn);/*配置子网掩码*/
//    setGAR(gWIZNETINFO.gw);/*配置默认网关*/
//    setSIPR(gWIZNETINFO.ip);/*配置Ip地址*/
    NetworkParameterConfiguration(); // 初始化网络参数配置 MAC IP等
    ChipParametersConfiguration();   // 初始化芯片

    uint8_t version = 0;
    version = getVERSIONR();
    rt_kprintf("W5500 VERSION : %d\r\n", version);

    setRTR(2000); /* 设置溢出时间值 */
    setRCR(3);    /* 设置最大重新发送次数 */
    return 0;
}

/**
 * @description: 设置IP地址
 */
void Set_IP(uint8_t ip1, uint8_t ip2, uint8_t ip3, uint8_t ip4) {
    uint8_t ip[4] = {ip1, ip2, ip3, ip4};
    setSIPR(ip);
}

/**
 * @description: 设置MAC地址
 */
void Set_MAC(uint8_t mac1, uint8_t mac2, uint8_t mac3, uint8_t mac4, uint8_t mac5, uint8_t mac6){
    uint8_t mac[6] = {mac1, mac2, mac3, mac4, mac5, mac6};
    setSHAR(mac);
}

/**
 * @description: 设置网关地址
 */
void Set_GW(uint8_t gw1, uint8_t gw2, uint8_t gw3, uint8_t gw4)
{
    uint8_t gw[4] = {gw1, gw2, gw3, gw4};
    setGAR(gw);
}

/**
 * @description: 设置子网掩码
 */
void Set_SUB(uint8_t sn1, uint8_t sn2, uint8_t sn3, uint8_t sn4)
{
    uint8_t sn[4] = {sn1, sn2, sn3, sn4};
    setSUBR(sn);
}

/**
 * @description: 设置DNS
 */
void Set_DNS(uint8_t dns1, uint8_t dns2, uint8_t dns3, uint8_t dns4)
{
    Set_DNS(dns1, dns2, dns3, dns4);
}

void Set_Debug_Net(uint8_t gw3, uint8_t ip4)
{
    uint8_t ip_addr[4] = {192, 168, gw3, ip4};
    uint8_t gw[4] = {192, 168, gw3, 1};
    
    memcpy(g_qf_device.phy.IP, ip_addr, 4);
    memcpy(g_qf_device.phy.Gateway, gw, 4);
    
    TerParamUpdate();

    Software_Reset();
}

//INIT_BOARD_EXPORT(W5500_ChipInit);
